/* 
 * File:   StackList.cpp
 * Author: Gab'z
 * 
 * Created on 28 mai 2012, 11:39
 */

#include "StackList.h"

namespace calculator {
    Logger* StackList::log = LoggerManager::getInstance()->getLogger("StackList");

    StackList* StackList::instance = 0;

    StackList::StackList() {
        Stack* stack = new Stack();
        _stackList.push_front(stack);
        _iteratorCurrentStack = _stackList.begin();
    }

//    StackList::StackList(const StackList& orig) {
//        for (std::list<Stack*>::const_iterator it = orig._stackList.begin();
//                it != orig._stackList.end();
//                it++) {
//            _stackList.push_back((*it)->clone());
//        }
//
//        //placement de l'itérateur sur la copie de l'élément pointé par l'itérateur d'origine
//        _iteratorCurrentStack = _stackList.begin();
//        while (*_iteratorCurrentStack != *(orig._iteratorCurrentStack)) {
//            _iteratorCurrentStack++;
//        }
//    }

    StackList::~StackList() {
        for (std::list<Stack*>::iterator it = _stackList.begin();
                it != _stackList.end();
                it++) {
            delete *it;
        }
        _stackList.clear();
    }

    StackList* StackList::clone() const {
        StackList* stackList = new StackList();
        delete *(stackList->_stackList.begin());
        stackList->_stackList.clear();
        for (std::list<Stack*>::const_iterator it = _stackList.begin();
                it != _stackList.end();
                it++) {
            stackList->_stackList.push_back((*it)->clone());
        }
        return stackList;
    }

    Stack* StackList::getStack(const unsigned int n) const throw (ContextException) {
        unsigned int index = 0;
        std::list<Stack*>::const_iterator it = _stackList.begin();
        while (index != n) {
            it++;
            index++;
        }
        if (it == _stackList.end()) throw ContextException("Out of StackList");
        return *it;
    }

    Stack* StackList::getCurrentStack() const {
        return *_iteratorCurrentStack;
    }

    unsigned int StackList::getCurrentStackIndex() const {
        log->trace("getCurrentStackIndex...");
        unsigned int index = 0;
        std::list<Stack*>::const_iterator it = _stackList.begin();
        while (it != _iteratorCurrentStack && it != _stackList.end()) {
            it++;
            index++;
        }
        log->trace("getCurrentStackIndex done");
        return index;
    }

    void StackList::setCurrentStack(const unsigned int n) throw (ContextException) {
        log->trace("setCurrentStack...");
        _iteratorCurrentStack = _stackList.begin();

        unsigned int i = 0;
        while (i != n && _iteratorCurrentStack != _stackList.end()) {
            i++;
            _iteratorCurrentStack++;
        }
        if (_iteratorCurrentStack == _stackList.end()) {
            throw ContextException("Out of stacklist");
        }
        log->trace("setCurrentStack done");
    }

    StackList* StackList::getInstance() {
        if (instance == 0) {
            instance = new StackList();
        }
        return instance;
    }

    void StackList::deleteInstance() {
        if (instance != 0) {
            delete instance;
        }
    }

    void StackList::newStack(const Stack* _stack) {
        log->trace("newStack...");
        Stack* stack;
        if (_stack == 0) {
            stack = new Stack();
        } else {
            stack = _stack->clone();
        }
        _stackList.insert(_stackList.end(), stack);
        _iteratorCurrentStack = _stackList.end();
        _iteratorCurrentStack--;
        log->trace("newStack done");
    }

    void StackList::removeCurrentStack() {
        log->trace("removeCurrentStack()...");
        if (!_stackList.empty()) {
            std::ostringstream oss;
            oss << "Current index of stackList = " << getCurrentStackIndex();
            log->trace(oss.str());

            std::list<Stack*>::iterator it = _iteratorCurrentStack;
            _iteratorCurrentStack--;
            delete *it;
            _stackList.erase(it);
            if (++_iteratorCurrentStack == _stackList.end()) _iteratorCurrentStack--;
            log->trace("removeCurrentStack() done");
            std::ostringstream oss2;
            oss2 << "Current index of stackList after removal = " << getCurrentStackIndex();
            log->trace(oss2.str());
        } else {
            log->error("Empty stackList");
        }
    }

    void StackList::duplicateCurrentStack() {
        log->trace("duplicateStack()");
        if (!_stackList.empty()) {
            std::ostringstream oss;
            oss << "Current index of stackList = " << getCurrentStackIndex();
            log->trace(oss.str());
            Stack* stack = (*_iteratorCurrentStack)->clone();
            std::list<Stack*>::iterator it = _iteratorCurrentStack;
            it++;
            _stackList.insert(it, stack);
            _iteratorCurrentStack++;
            std::ostringstream oss2;
            oss2 << "Current index of stackList after duplicateCurrent = " << getCurrentStackIndex();
            log->trace(oss2.str());
        }


    }

    void StackList::insertStackAtIndex(Stack* stack, const unsigned int index) {
        _iteratorCurrentStack = _stackList.begin();
        unsigned int i = 0;
        while (i != index && _iteratorCurrentStack != _stackList.end()) {
            i++;
            _iteratorCurrentStack++;
        }
        _stackList.insert(_iteratorCurrentStack, stack);
        if (++_iteratorCurrentStack == _stackList.end()) _iteratorCurrentStack--;
    }

    bool StackList::empty() const {
        return _stackList.empty();
    }
}
